class Object
  def check_type(typename) 
    unless is_a?(typename)
      raise TypeError.new("object isn't instance of #{typename}, but is a #{self.class}") 
    end
    return self
  end
end

class File
  def self.write(filename, content)
    File.open(filename, 'w') { |file| file.write(content) }
  end
end

class Hash
  def to_s
    items = []
    for key in keys.sort
      items << "#{key}: #{self[key]}"
    end
    return items.join("\n")
  end
end

class Module
  @@__abstract_methods = Hash.new
  
  def self_instance_method(method) # method String
    unless instance_methods(false).include?(method)
      raise NotImplementedError.new("not implemented abstract method ‘#{method}’ in class `#{self}'")
    end
    return instance_method(method)
  end
  
  def superclasses
    return [superclass] + included_modules
  end
  
  #
  # Abstract
  #
  
  def abstracts_methods
    return @@__abstract_methods[self] || []
  end
  
  def set_abstract_method(method) # method Symbol
    @@__abstract_methods[self] = [] unless @@__abstract_methods.key?(self)
    @@__abstract_methods[self] << method.id2name
  end
  
  def check_abstracts_methods
    superclasses.each{ |mod| check_abstracts_methods_of mod }
  end
  
  def check_abstracts_methods_of(baseclass)
    for name in baseclass.abstracts_methods
      # verifica che il metodo sia implementato nella classe derivata
      method_super = baseclass.instance_method(name)
      method_self  = self_instance_method(name)
      
      # e che abbia la stessa cardinalità di quello della classe base
      unless method_self.arity == method_super.arity
        raise ArgumentError.new("incompatible method #{name} in class #{self}")
      end
    end
  end
  
  #
  # Override
  #
  
  def instance_methods_all_base(method)
    for mod in superclasses
      begin
        return mod, mod.instance_method(method)
      rescue
      end
    end
    
    raise SyntaxError.new("method #{method} in class #{self} not overridable")
  end
  
  def check_override_method(method)
    method = method.id2name
    base, method_base = instance_methods_all_base(method)
    method_derived    = self_instance_method(method)
    
    unless method_base.arity == method_derived.arity
      raise ArgumentError.new("incompatible method #{method} in class #{self} with class #{base}")
    end
  end
end